package com.snc.util;

import com.snc.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.imageio.ImageIO;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * 上传的文件处理工具类
 *
 * @author shenyt
 */
public class MultipartFileUtil {

    public static final Logger logger = LoggerFactory.getLogger(MultipartFileUtil.class);

    /**
     * 存放图片的文件夹
     */
    public static final String IMAGE_FOLDER = "/cdn/images/";
    /**
     * 存放视频的文件夹
     */
    public static final String VIDEO_FOLDER = "/cdn/video/";

    /**
     * 存放apk的文件夹
     */
    public static final String APK_FOLDER = "/cdn/apk/";

    /**
     * 存放PPT的文件夹
     */
    public static final String PPT_FOLDER = "/cdn/ppt/";

    /**
     * 存放PDF的文件夹
     */
    public static final String PDF_FOLDER = "/cdn/pdf/";

    /**
     * 图片后缀
     */
    public static final String[] IMAGE_SUFFIXS = {"JPEG", "JPG", "PNG", "BPM", "GIF", "JPG"};

    /**
     * 图片大小，500k
     */
    public static final Long IMAGE_MAX_SIZE = 1024 * 1024 * 500L;

    /**
     * 视频后缀
     */
    public static final String[] VIDEO_SUFFIXS = {"AVI", "RMVB", "MP4", "MKV", "WMV", "FLV", "MOV", "MP3", "VOB"};

    /**
     * app后缀
     */
    public static final String[] APP_SUFFIXS = {"APK"};

    /**
     * 视频大小，100m
     */
    public static final Long VIDEO_MAX_SIZE = 1024 * 1024 * 104 * 100L;


    /**
     * 包装文件
     *
     * @param mfile 文件
     * @return
     */
    public static ContentBody resolve(MultipartFile mfile) {
        try {
            String filename = mfile.getOriginalFilename();
            ContentBody contentBody = new InputStreamBody(mfile.getInputStream(), filename);
            return contentBody;
        } catch (IOException e) {
            String message = e.getMessage();
            logger.error(message, e);
            throw new RuntimeException(message);
        }
    }

    /**
     * 根据文件名称获取后缀名
     *
     * @param fileName 文件名称
     * @return 结果
     */
    public static String getSuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * 获取项目根路径
     *
     * @return 结果
     */
    public static String getRootPath() {
        String classPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        String rootPath = "";
        //windows下
        if ("\\".equals(File.separator)) {
            rootPath = classPath.substring(1, classPath.indexOf("/WEB-INF/classes"));
            rootPath = rootPath.replace("/", "\\");
        }
        //linux下
        if ("/".equals(File.separator)) {
            rootPath = classPath.substring(0, classPath.indexOf("/WEB-INF/classes"));
            rootPath = rootPath.replace("\\", "/");
        }
        return rootPath;
    }

    /**
     * 判断文件是否未空，或者没有数据
     *
     * @param file 文件
     * @return 结果
     */
    public static boolean isEmpty(MultipartFile file) {
        return file == null || file.getSize() == 0 || "".equals(file.getOriginalFilename().trim());
    }

    /**
     * 生成缩略图，根据宽度自动缩放高度
     *
     * @param imagePath 原图 相对路径
     * @param width     缩略图宽度
     * @return 结果
     */
    public static String generateThumbnail(String imagePath, double width) {

        //srcURl 原图地址；deskURL 缩略图地址；comBase 压缩基数；scale 压缩限制(宽/高)比例

        MemoryCacheImageInputStream mciis = null;
        try {
            mciis = new MemoryCacheImageInputStream(new FileInputStream(getRootPath() + imagePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Image src = null;
        try {
            src = ImageIO.read(mciis);
        } catch (IOException e) {
            e.printStackTrace();
        }
        double srcHeight = src.getHeight(null);
        double srcWidth = src.getWidth(null);
        double deskHeight = 0;//缩略图高
        double deskWidth = 0;//缩略图宽

        //根据比例计算宽度
        double height = (width / srcWidth) * srcHeight;

        if (srcWidth > srcHeight) {

            if (srcWidth > width) {
                if (width / height > srcWidth / srcHeight) {
                    deskHeight = height;
                    deskWidth = srcWidth / (srcHeight / height);
                } else {
                    deskHeight = width / (srcWidth / srcHeight);
                    deskWidth = width;
                }
            } else {

                if (srcHeight > height) {
                    deskHeight = height;
                    deskWidth = srcWidth / (srcHeight / height);
                } else {
                    deskHeight = srcHeight;
                    deskWidth = srcWidth;
                }

            }

        } else if (srcHeight > srcWidth) {
            if (srcHeight > (height)) {
                if ((height) / width > srcHeight / srcWidth) {
                    deskHeight = srcHeight / (srcWidth / width);
                    deskWidth = width;
                } else {
                    deskHeight = height;
                    deskWidth = (height) / (srcHeight / srcWidth);
                }
            } else {
                if (srcWidth > width) {
                    deskHeight = srcHeight / (srcWidth / width);
                    deskWidth = width;
                } else {
                    deskHeight = srcHeight;
                    deskWidth = srcWidth;
                }

            }

        } else if (srcWidth == srcHeight) {

            if (width >= (height) && srcHeight > (height)) {
                deskWidth = (height);
                deskHeight = (height);
            } else if (width <= (height) && srcWidth > width) {
                deskWidth = width;
                deskHeight = width;
            } else if (width == (height) && srcWidth < width) {
                deskWidth = srcWidth;
                deskHeight = srcHeight;
            } else {
                deskHeight = srcHeight;
                deskWidth = srcWidth;
            }

        }
        BufferedImage tag = new BufferedImage((int) deskWidth, (int) deskHeight,
                BufferedImage.TYPE_3BYTE_BGR);
        tag.getGraphics().drawImage(src, 0, 0, (int) deskWidth, (int) deskHeight, null); //绘制缩小后的图

        //转换成image
        Image big = tag.getScaledInstance((int) deskWidth, (int) deskHeight, Image.SCALE_DEFAULT);
        BufferedImage inputbig = new BufferedImage((int) deskWidth, (int) deskHeight, BufferedImage.TYPE_INT_BGR);
        inputbig.getGraphics().drawImage(tag, 0, 0, (int) deskWidth, (int) deskHeight, null); //画图

        //取得当前上传文件的文件名称
        String suffix = MultipartFileUtil.getSuffix(imagePath);
        //重命名上传后的文件名
        String fileName = UUID.randomUUID().toString() + "." + suffix.toLowerCase();

        //文件夹路径
        String filePath = getRootPath() + IMAGE_FOLDER + "/";
        File f = new File(filePath);
        // 目录已存在创建文件夹
        if (!f.exists()) {
            f.mkdirs();// 目录不存在的情况下，会抛出异常
        }

        //定义上传路径
        String path = filePath + fileName;

        try {
            ImageIO.write(inputbig, suffix.toLowerCase(), new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return IMAGE_FOLDER + "/" + fileName;
    }

    /**
     * 判断图片是否满足要求
     *
     * @param image 图片
     */
    public static void validImage(MultipartFile image) {
        //图片类型和大小判断
        String suffix = getSuffix(image.getOriginalFilename());
        if (!Arrays.asList(IMAGE_SUFFIXS).contains(suffix.toUpperCase())) {
            throw new BusinessException("图片只支持JPEG、JPG、PNG、BPM、GIF、JPG格式");
        }
        if (image.getSize() > IMAGE_MAX_SIZE) {
            throw new BusinessException("图片大小不能超出500kb");
        }
    }

    /**
     * 删除指定的附件信息
     *
     * @param paths
     */
    public static void deleteFile(List<String> paths) {
        for (String s : paths) {
            if (StringUtils.isNoneEmpty(s)) {
                File file = new File(getRootPath() + s);
                if (file.exists()) {
                    file.delete();
                }
            }

        }
    }

    /**
     * 图片上传
     *
     * @param image 被上传的文件
     * @return 上传后的相对路径
     */
    public static String uploadImage(MultipartFile image) {
        if (isEmpty(image)) {
            return null;
        }
        MultipartFileUtil.validImage(image);
        return uploadFile(IMAGE_FOLDER, image);
    }


    /**
     * 视频上传
     *
     * @param video 被上传的视频
     * @return 上传后的相对路径
     */
    public static String uploadVideo(MultipartFile video) {
        if (isEmpty(video)) {
            return null;
        }

        //图片类型和大小判断
        String suffix = getSuffix(video.getOriginalFilename());
        if (!Arrays.asList(VIDEO_SUFFIXS).contains(suffix.toUpperCase())) {
            throw new BusinessException("视频只支持MP4、RMVB、AVI、MOV、VOB、RM、MP3、WMV、FLV格式");
        }
        if (video.getSize() > VIDEO_MAX_SIZE) {
            throw new BusinessException("图视频片大小不能超出100Mb");
        }

        return uploadFile(VIDEO_FOLDER, video);
    }

    /**
     * 上传apk文件
     *
     * @param apk
     * @return
     */
    public static String uploadApk(MultipartFile apk) {
        if (isEmpty(apk)) {
            return null;
        }

        //类型判断
        String suffix = getSuffix(apk.getOriginalFilename());
        if (!Arrays.asList(APP_SUFFIXS).contains(suffix.toUpperCase())) {
            throw new BusinessException("应用app只支持apk格式");
        }


        return uploadFile(APK_FOLDER, apk);
    }


    /**
     * 上传文件
     *
     * @param prefix 存放文件的跟路径
     * @param file   文件
     * @return 返回相对路径
     */
    public static String uploadFile(String prefix, MultipartFile file) {
        //取得当前上传文件的文件名称
        String myFileName = file.getOriginalFilename();
        String suffix = myFileName.substring(myFileName.lastIndexOf(".") + 1);
        //重命名上传后的文件名
        String fileName = UUID.randomUUID().toString() + "." + suffix.toLowerCase();

        //文件夹路径
        String filePath = getRootPath() + prefix + "/";
        File f = new File(filePath);
        // 目录已存在创建文件夹
        if (!f.exists()) {
            f.mkdirs();// 目录不存在的情况下，会抛出异常
        }

        //定义上传路径
        String path = filePath + fileName;
        //创建文件
        File localFile = new File(path);
        try {
            file.transferTo(localFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return prefix + "/" + fileName;
    }

    /**
     * 从请求中获取文件
     *
     * @param request 请求
     * @return
     */
    public static List<MultipartFile> getFiles(HttpServletRequest request) {

        List<MultipartFile> files = new ArrayList<MultipartFile>();
        //创建一个通用的多部分解析器
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        //判断 request 是否有文件上传,即多部分请求
        if (multipartResolver.isMultipart(request)) {
            //转换成多部分request
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            if (multiRequest.getMultiFileMap().size() > 0) {
                List<MultipartFile> fileList = multiRequest.getMultiFileMap().get("fileUpload");
                for (MultipartFile file : fileList) {
                    if (!contains(files, file) && file.getSize() != 0 && !"".equals(file.getOriginalFilename())) {
                        files.add(file);
                    }
                }
            }
        }

        return files;
    }


    /**
     * 查询文件中是否包含该文件，根据一次请求的size + name来比较。
     *
     * @param files
     * @param file
     * @return
     */
    public static boolean contains(List<MultipartFile> files, MultipartFile file) {
        for (MultipartFile f : files) {
            if (f.getOriginalFilename().equals(file.getOriginalFilename())
                    && f.getSize() == file.getSize()) {
                return true;
            }
        }
        return false;
    }

}
